#Issue# Best Practice on Token-Refresh Implementation

#Issue# Best Practice on Token-Refresh Implementation

本文讨论服务端自动刷新令牌过期时间的最佳实践。


场景引入

在使用 Token 机制进行 Auth 时,出于安全性的考虑我们很容易想到需要为令牌设置过期时间,然而小菜如我往往也忽略了体验性的问题即“自动延长过期时间”以保持活跃用户在线,引用 Auth0 的一段话意会一哈——

“一个好的模式是在它过期之前刷新令牌。将令牌过期时间设置为一周,并在每次用户打开Web应用程序并每隔一小时刷新令牌。如果用户超过一周没有打开过应用程序,那他们就需要再次登录,这是可接受的Web应用程序UX(用户体验)。要刷新令牌,API需要一个新的端点,它接收一个有效的,没有过期的JWT,并返回与新的到期字段相同的签名的JWT。然后Web应用程序会将令牌存储在某处。”

我们把问题拆分为两个维度

  1. 单点登录:单点登录 (Single Sign On, SSO),在应用场景上分为同域单点登录跨域单点登录,在实现方案上分为 OAuthCAS,etc…单点登录也是一个很有趣的需求场景,以后有机会考虑开专栏讨论下个人的一些浅见,现在假设我们已经站在巨人的肩膀上,Token 加密内容的生成和验证将作为先验知识不会在本文中过多地解释
  2. 令牌刷新本文重点在于思考“如何优雅地设置 Token 有效时间”。在真正动手前需要考量几个问题,并且要十分注意实际生产中容易踩到的坑,回到算法本身而言寻求从静态到动态的优化与提升。

灵魂三问

主体是谁?

令牌刷新的主体,可以是服务端,可以是客户端,怎么做选择题Ⅰ?

  • 服务端:控制令牌信息更灵活,实现较简单
  • 客户端:控制交互体验更灵活,实现较繁琐

客体是谁?

令牌刷新的客体,可以是加密内容,可以是过期时间,怎么做选择题Ⅱ?

  • 加密内容:优点是可以使用 JWT 而无需存储;缺点是频繁生成新的令牌浪费空间,维护多个令牌容易出现安全问题和并发问题,常见解决方案有 refresh token 方案middleware 方案
  • 过期时间:优点是可以使用 Random Ticket 类似于“单例”而没有空间、安全、并发等的问题;缺点是需要维护额外的数据库存储,一般来说考虑到令牌将被热点访问和定期删除,Redis 是最佳的实践,使用 MySQL / MongoDB 在单机和低并发的情况下也是可行的。

在什么条件下?

  • < 临界过期时间:无需登录,令牌不会刷新
  • 临界过期时间 ~ 预设过期时间:无需登录,令牌自动刷新
  • > 预设过期时间:需要登录,新的令牌周期

具体实现

综合以上,下面提供服务端自动刷新令牌过期时间的简要解决方案。

静态刷新

statically refresh

  • 优点:实现方式简单粗暴,每验证一次就更新一次。
  • 缺点:更新太过频繁,性能受损,令牌可能出现“几乎不会过期”有悖设计初衷。

动态刷新

dynamically refresh

  • 优点:设置过期临界,对更新的条件做了限制,提升性能,使用合理。
  • 缺点:维护两个过期时间——临界过期时间和预设过期时间。

踩坑警告

  1. 注意重置密码时同步地处理令牌
  2. 注意浏览器多选项卡并发操作的影响
  3. 注意过期令牌妥善处理,可以放着不管 or 定期删除,但是不能直接覆盖(👉#Microservice# Golang Microservice 工程开发踩坑记录👈)

参考链接

  1. JWT(JSON Web Token)自动延长到期时间
  2. 对于token的认证,如何保证token的及时刷新?
  3. Shiro整合JWT+Token过期刷新,全都帮你整好了
  4. 采用JWT有效期内刷新Token方案,解决并发请求问题
  5. Token 过期的问题

# Golang

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×